package com.bensonbasement.snorflux.memory;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import com.bensonbasement.snorflux.memory.WorldElementInfo.WorldElementType;

public class Memory implements Serializable {
	
	private final Set<Long> visibleSpaceIDs;
	private final RWorld world;
	
	public Memory() {
		this.visibleSpaceIDs = new HashSet<Long>();
		this.world = new RWorld(this);
	}
	
	public boolean isSpaceVisible(long spaceID) {
		return visibleSpaceIDs.contains(spaceID);
	}
	
	public void updateInfo(WorldElementInfo info) {
		
		if (info.getType() == WorldElementType.SPACE) {
			SpaceInfo spaceInfo = (SpaceInfo) info;
			RSpace space = (RSpace) this.world.getWorldElement(info.getWorldElementID());
			if (space == null) {
				
				RLevel level = world.getLevel(spaceInfo.getLevelNum());
				if (level == null) {
					level = new RLevel(this.world,spaceInfo.getLevelNum());
					world.addLevel(level);
				}
				space = new RSpace(this.world,spaceInfo,level);
				this.world.storeWorldElement(space);
				level.addSpace(space);
			}
			else {
				space.setInfo(spaceInfo);
			}
		}
		else if (info.getType() == WorldElementType.BIGENTITY) {
			BigEntityInfo bigEntityInfo = (BigEntityInfo) info;
			RBigEntity entity = (RBigEntity) this.world.getWorldElement(info.getWorldElementID());
			if (entity == null) {
				entity = new RBigEntity(this.world,bigEntityInfo);
				this.world.storeWorldElement(entity);
			}
			else {
				entity.setInfo(bigEntityInfo);
			}
		}
		else if (info.getType() == WorldElementType.SMALLENTITY) {
			SmallEntityInfo smallEntityInfo = (SmallEntityInfo) info;
			RSmallEntity entity = (RSmallEntity) this.world.getWorldElement(info.getWorldElementID());
			if (entity == null) {
				entity = new RSmallEntity(this.world,smallEntityInfo);
				this.world.storeWorldElement(entity);
			}
			else {
				entity.setInfo(smallEntityInfo);
			}
		}
	}
	
	public void forgetEntity(long worldElementID) {
		REntity entity = (REntity) this.world.getWorldElement(worldElementID);
		entity.leaveLocation();
		this.world.deleteWorldElement(worldElementID);
	}

	public RWorld getWorld() {
		return world;
	}
	
	public void updateVisibility(Set<Long> newlyVisibleSpaceIDs, Set<Long> newlyNonVisibleSpaceIDs) {
		this.visibleSpaceIDs.removeAll(newlyNonVisibleSpaceIDs);
		this.visibleSpaceIDs.addAll(newlyVisibleSpaceIDs);
	}
}
